home *** CD-ROM | disk | FTP | other *** search
- /*
- * uubatch.c, uubatch version 1.0.5
- *
- * uubatch : a uucp rmail batching program.
- *
- * Authors : Gil Tene (devil@hellnet.org).
- * Baruch Cochavy (blue@dduster.hellnet.org)
- *
- * Usage :
- * uubatch [-c] [-B n] [-C n] [-S n] [-T n] node [node2...]
- *
- * This program will attempt to batch the given uucp nodes' queued
- * jobs into uudebat or uucdebat jobs. It takes care of the entire
- * batching process including uucp locking (via an external uucplock
- * program).
- *
- * External uubatch program binaries (specificaly uubatch) are assumed
- * be runnable with the same path header uubatch was run with (as parsed
- * from argv[0]). This means that uucplock should usually be in the same
- * directory as uubatch.
- *
- * The program scans each spool directory for C.<> files, which are
- * taken as the names of jobs to consider for batching (if they
- * meet the batching criteria below).
- *
- * uubatch accepts the following parameteres:
- *
- * node, node2... :
- * The uucp nodes to run on.
- *
- * -c : compression on (default is off)
- *
- * -B n : MAX_BYTES = n (default DF_MAX_BYTES)
- * MAX_BYTES is the maximum size (in bytes) of an rmail
- * message or a uudebat job that may be added to a batch
- * Jobs larger than this parameter are not batched.
- *
- * -C n : MAX_CBYTES = n (default DF_MAX_CBYTES)
- * MAX_FILE_CBYTES is the maximum size (in bytes) of a
- * uucdebat job's compressed data file that may be added
- * to a batch. uucdebat jobs with compressed data files
- * larger than this parameter are not rebatched.
- *
- * -S n : CRITICAL_SIZE = n (default DF_CRITICAL_SIZE)
- * CRITICAL_BATCH_SIZE is the batch size (in bytes)
- * after which we send the batch off and start a new
- * one. Be aware of the fact that the actual MAXIMUM
- * batch size is actually the greater one of :
- *
- * CRITICAL_BATCH_SIZE + MAX_BYTES_FOR_BATCH
- *
- * CRITICAL_BATCH_SIZE +
- * uncompressed(MAX_CBYTES_FOR_BATCH)
- *
- * -T n : min_time_before_batch = n seconds
- * (defaults to MIN_TIME_BEFORE_BATCH)
- * This is the age of a job (in seconds) before
- * it may be considered for batching.
- *
- * Each queued job will be examined to see if the job should
- * be batched. If a job need not be batched then the program simply
- * skips over it. If the job needs to be batched, and the batching
- * succeeds and the batch is sccessfully uuxe'd, the job's data files
- * are deleted.
- *
- *
- * Batching criteria :
- *
- * rmail jobs with Data less than MAX_BYTES bytes
- * and more than min_time_before_batch sec. old will be batched.
- *
- * uudebat jobs with Data less than MAX_BYTES and
- * more than min_time_before_batch sec. old will be batched.
- *
- * uucdebat jobs with compressed data less than MAX_CBYTES
- * and more than min_time_before_batch sec. old will be batched.
- *
- * Batching will ONLY be done if at least one rmail job is
- * encountered in the node's spool directory. This saves
- * on unneeded re-batching of uudebat and uucdebat jobs.
- *
- */
-
- # include <stdio.h>
- #ifdef BSD
- #include <strings.h>
- #else
- #define index(_a,_b) strchr(_a,_b)
- #define rindex(_a,_b) strrchr(_a,_b)
- #endif
-
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <dirent.h>
-
- #include "patchlevel.h"
-
- /* see main()'s flags description below for explanation of the meaning */
- /* of the following three default values : */
-
- #define DF_MAX_BYTES 60000
- #define DF_MAX_CBYTES 35000
- #define DF_CRITICAL_SIZE 100000
-
-
- #ifndef MIN_TIME_BEFORE_BATCH
- #define MIN_TIME_BEFORE_BATCH 40
- #endif
-
- #ifndef LINE_LENGTH
- #define LINE_LENGTH 512
- #endif
-
- #ifndef MAX_DF2_LINES
- #define MAX_DF2_LINES 80
- #endif
-
- #ifndef MAX_JOBS_PER_BATCH
- #define MAX_JOBS_PER_BATCH 100
- #endif
-
- #ifndef MAX_REGISTERED_BATCHES
- #define MAX_REGISTERED_BATCHES 20
- #endif
-
- #ifndef MAX_FILE_NAME
- #define MAX_FILE_NAME ((size_t)40)
- #endif
-
- char jobnames[MAX_REGISTERED_BATCHES][MAX_FILE_NAME+1];
- char df1_names[MAX_REGISTERED_BATCHES][MAX_FILE_NAME+1];
- char df2_names[MAX_REGISTERED_BATCHES][MAX_FILE_NAME+1];
- int jobs_uucdebat[MAX_REGISTERED_BATCHES];
- int registered_batches;
-
- char del_jobnames[MAX_JOBS_PER_BATCH][MAX_FILE_NAME+1];
- char del_df1_names[MAX_JOBS_PER_BATCH][MAX_FILE_NAME+1];
- char del_df2_names[MAX_JOBS_PER_BATCH][MAX_FILE_NAME+1];
- int jobs_this_batch;
-
- char df2lines[MAX_DF2_LINES][LINE_LENGTH+1];
- int df2nlines;
-
- typedef struct _node_rec { struct _node_rec *next; char *name; } node_rec;
- node_rec *first_node=NULL,*curr_node=NULL,*last_node=NULL;
-
- char batchname[L_tmpnam];
- char uubatch_bin_path[256];
-
- FILE *bfile = (FILE *) NULL;
- FILE *cf = (FILE *) NULL;
- FILE *df1 = (FILE *) NULL;
- FILE *df2 = (FILE *) NULL;
-
- int total_rmail_jobs;
-
- long max_bytes, max_cbytes, critical_size, accumulated_size;
- int min_time_before_batch = MIN_TIME_BEFORE_BATCH;
-
- /* General exit and diagnostics routines : */
-
- my_exit(n)
- {
- if (bfile) fclose(bfile);
- unlink(batchname);
- exit(n);
- }
-
- pe_exit(s,n)
- char *s;
- int n;
- {
- perror(s);
- my_exit(n);
- }
-
- #define pe_ret(_st,_nn) \
- { \
- perror(_st); \
- if (cf) fclose(df1); \
- if (df1) fclose(df1); \
- if (df2) fclose(df2); \
- return(_nn); \
- }
-
- pdn_exit(s,n,ne)
- char *s;
- int n,ne;
- {
- char str[120];
- sprintf(str,s,n);
- fprintf(stderr,"uubatch : Diagnostic %03d: %s\n",ne,str);
- my_exit(ne);
- }
-
- #define pdn_ret(_st,_nn,_ne) \
- { \
- char str[120]; \
- sprintf(str,_st,_nn); \
- fprintf(stderr,"uubatch : Diagnostic %03d: %s\n",_ne,str); \
- if (cf) fclose(df1); \
- if (df1) fclose(df1); \
- if (df2) fclose(df2); \
- return (_ne); \
- }
-
- pd(s,n)
- char *s;
- int n;
- {
- fprintf(stderr,"uubatch : Diagnostic %03d: %s\n",n,s);
- }
-
- pds(s,s1,n)
- char *s;
- int n;
- {
- fprintf(stderr,"uubatch : Diagnostic %03d: %s %s\n",n,s,s1);
- }
-
- #define pd_ret(_st,_nn) \
- { \
- fprintf(stderr,"uubatch : Diagnostic %03d: %s\n",_nn,_st); \
- if (cf) fclose(df1); \
- if (df1) fclose(df1); \
- if (df2) fclose(df2); \
- return _nn; \
- }
-
- #define pds_ret(_st,_nn) \
- { \
- fprintf(stderr,"uubatch : Diagnostic %03d: %s\n",_nn,_st); \
- return _nn; \
- }
-
- p_exit(s,n)
- char *s;
- int n;
- {
- fprintf(stderr,"uubatch : Error %03d: %s\n",n,s);
- my_exit(n);
- }
-
- #define p_ret(_st,_n) \
- { \
- fprintf(stderr,"uubatch : Error %03d: %s\n",_n,_st); \
- if (cf) fclose(df1); \
- if (df1) fclose(df1); \
- if (df2) fclose(df2); \
- return(_n); \
- }
-
- /* Now for real code... */
-
- #define str_eq(_s1,_s2) (!strncmp(_s1,_s2,strlen(_s2)))
-
- /* add_node() : add a node name to a [global] linked list of node names : */
-
- static int
- add_nodename(name)
- char *name;
- {
- if (last_node)
- {
- last_node->next = (node_rec *) malloc(sizeof(node_rec));
- last_node = last_node->next;
- }
- else
- first_node = last_node = (node_rec *) malloc(sizeof(node_rec));
-
- last_node->next = NULL;
- last_node->name = (char *) malloc(strlen(name)+1);
- strcpy(last_node->name,name);
- }
-
- /* lock_node() : lock a uucp node : */
-
- static int
- lock_node(name)
- char *name;
- {
- char command[256];
- if (*uubatch_bin_path!='\0')
- sprintf(command, "%s/uucplock lock %s 2> /dev/null",
- uubatch_bin_path, name);
- else
- sprintf(command, "uucplock lock %s 2> /dev/null",
- name);
-
- return (system(command));
- }
-
- /* unlock_node() : unlock a uucp node : */
-
- static int
- unlock_node(name)
- char *name;
- {
- char command[256];
- if (*uubatch_bin_path!='\0')
- sprintf(command, "%s/uucplock unlock %s 2> /dev/null",
- uubatch_bin_path, name);
- else
- sprintf(command, "uucplock unlock %s 2> /dev/null",
- name);
-
- return (system(command));
- }
-
-
- /* get_names() : */
- /* extracts a file's local and remote names from a C.<> file line */
- /* it checks the remote name for a proper prefix (passed to us). */
-
- get_names(line,pname,premote_name,rname_prefix)
- char *line,**pname,**premote_name,*rname_prefix;
- {
- char *end_of_names;
- *pname = line+2;
-
- if (!(*premote_name = index(*pname,' ')))
- pds_ret("Oops, no space after first file name in command file.",112);
-
- if (!str_eq((*premote_name)+1,rname_prefix))
- pds_ret("Oops, wrong remote name prefix in command file.",113);
-
- (*premote_name)[0] = '\0';
- (*premote_name)++;
-
- if (!(end_of_names = index(*premote_name,' ')))
- pds_ret("Oops, remote file name with no end in command file...",114);
-
- end_of_names[0] = '\0';
-
- return 0;
- }
-
-
-
- /* batch_job() : */
- /* This routine does most of the real work. It accepts a job name */
- /* and figures out if it needs to be batched. If it is an rmail job */
- /* it will batch it. If the job is a uudebat or uucdebat, it will */
- /* register for later re-batching, IF at least one rmail job is */
- /* found in the queue. */
-
- batch_job(jobname)
- char *jobname;
- {
- int i;
- char *df1_name, *df1_remote_name;
- char *df2_name, *df2_remote_name;
- char line1[LINE_LENGTH],line2[LINE_LENGTH],line[LINE_LENGTH];
- struct stat df1_status;
- int is_rmail,is_uudebat,is_uucdebat,line_state;
-
- cf = (FILE *) NULL;
- df1 = (FILE *) NULL;
- df2 = (FILE *) NULL;
-
- /* Do some nit-picking checks : */
-
- if (strlen(jobname) > MAX_FILE_NAME)
- p_ret("jobname too long.",5);
-
- if (!str_eq(jobname,"C."))
- p_ret("jobname must be C.<jobid>",10);
-
- if (!(cf = fopen(jobname,"r")))
- pe_ret("Can't open specified job file",15);
-
- if (fgets(line1,LINE_LENGTH,cf))
- {
- if (!fgets(line2,LINE_LENGTH,cf))
- pd_ret("Only one line in command file",20);
- }
- else
- p_ret("No lines in command file",25);
-
- if (line1[0]!='S')
- pd_ret("Oops, no S in line 1 of command file",30);
-
- if (line2[0]!='S')
- pd_ret("Oops, no S in line 2 of command file.",35);
-
- /* Now figure out the command file's names (local and remote), and */
- /* open it up : */
-
- if (get_names(line2,&df2_name,&df2_remote_name,"X."))
- return;
-
- if (strlen(df2_name)>MAX_FILE_NAME)
- p_ret("X. data file name too long.",40);
-
- if (!(df2=fopen(df2_name,"r")))
- pe_ret("Can't open X. data file.",45);
-
-
- /* scan the command file for batchable, command, while queuing the */
- /* lines for later use if it turns out we want to batch this file: */
-
- for ( df2nlines=is_rmail=is_uudebat=is_uucdebat=0;
- (fgets(line,LINE_LENGTH,df2)) && df2nlines<MAX_DF2_LINES;)
- {
- strcpy(df2lines[df2nlines++],line);
-
- /* only do checks on the beginning of file lines : */
- if (line[strlen(line)-1] == '\n')
- {
- if (str_eq(line,"C rmail")) is_rmail++;
- if (str_eq(line,"C uudebat")) is_uudebat++;
- if (str_eq(line,"C uucdebat")) is_uucdebat++;
- }
- }
-
- /* Figure out if all is kosher, and if there is a batchable command: */
-
- if (df2nlines==MAX_DF2_LINES)
- pd_ret("Too many lines in X. data file.",50);
-
- if (!(is_rmail+is_uudebat+is_uucdebat))
- pd_ret("No rmail, uudebat or uucdebat in X. data file...",55);
-
- if (is_rmail+is_uudebat+is_uucdebat>1)
- pd_ret("More than one rmail or uudebat, I won't do it!",60);
-
- /* So it's a batchable command, let's figure out stuff about it's */
- /* data file (name, remote name, age, size) : */
-
- if (get_names(line1,&df1_name,&df1_remote_name,"D."))
- return;
-
- if (strlen(df1_name)>MAX_FILE_NAME)
- p_ret("D. data fiel name too long.",65);
-
- if (!(df1=fopen(df1_name,"r")))
- pe_ret("Can't open D. data file.",70);
-
- /* get status of df1 : */
- fstat(fileno(df1), &df1_status);
-
- /* Check if it is not too old : */
-
- if (time(NULL) - df1_status.st_mtime < min_time_before_batch)
- pdn_ret("Data file is too new (%d sec), next time maybe.",
- time(NULL) - df1_status.st_mtime,75);
-
- /* Check if it is not too big : */
-
- if ( ( (is_rmail || is_uudebat) &&
- (df1_status.st_size>max_bytes)
- ) ||
- ( is_uucdebat && (df1_status.st_size>max_cbytes)
- )
- )
- pd_ret("file to big, not put in batch.",80);
-
-
- /* If we get to this point, we know we want to batch the job. */
-
-
- /* BATCH it : */
-
- /* rmail jobs need to have their name printed on top, and */
- /* their data file contents included with # preceding each */
- /* line. For uudebat and uucdebat the we will register the */
- /* batch for later rebatching, only done if at least one rmail */
- /* job is found in the queue. */
-
- if (is_rmail) /* for rmail jobs, batch the X. file */
- {
-
- /* write df2's name and contents in : */
- fprintf(bfile,"%s\n",df2_remote_name);
- accumulated_size += strlen(df2_remote_name) + 1;
-
- line_state = 0;
- for (i=0;i<df2nlines;i++)
- {
- /* if we are at the BEGINNING of a line, add a '#' to it : */
-
- if (!line_state)
- putc('#',bfile);
-
- fputs(df2lines[i],bfile);
-
- accumulated_size += strlen(df2lines[i]) + 1;
-
- /* set line state for next line: if this line was \n */
- /* terminated, then the we are at the beginning of a line, */
- /* otherwise we are in the middle of one : */
-
- line_state = index(df2lines[i],'\n') ? 0 : 1;
- }
-
- /* now write df1's name and contents in : */
-
- fprintf(bfile,"%s\n",df1_remote_name);
- accumulated_size += strlen(df1_remote_name) + 1;
-
- line_state = 0;
- while (fgets(line,LINE_LENGTH,df1))
- {
- /* if we are at the BEGINNING of a line, add a '#' to it : */
-
- if (!line_state)
- putc('#',bfile);
-
- fputs(line,bfile);
-
- accumulated_size += strlen(line) + 1;
-
- /* set line state for next line: if this line was \n */
- /* terminated, then the we are at the beginning of a line, */
- /* otherwise we are in the middle of one : */
-
- line_state = index(line,'\n') ? 0 : 1;
- }
-
- /* mark job's files for deletion : */
- strcpy(del_jobnames[jobs_this_batch],jobname);
- strcpy(del_df1_names[jobs_this_batch],df1_name);
- strcpy(del_df2_names[jobs_this_batch++],df2_name);
-
- total_rmail_jobs++;
- }
- else
- if (registered_batches<MAX_REGISTERED_BATCHES)
- {
- /* Register the batch for later re-batching if usefull. */
- /* Note that the are not likely to be many batch jobs */
- /* eligable for rebatching (in terms of size and age) */
- /* and that there is no harm in not registering some */
- /* of them. They will be picked up by later runs */
- /* if too many exist now... */
-
- strcpy(jobnames[registered_batches],jobname);
- strcpy(df1_names[registered_batches],df1_name);
- strcpy(df2_names[registered_batches],df2_name);
- jobs_uucdebat[registered_batches++] = is_uucdebat;
- }
-
- /* close cf,df1,df2 we don't them it any more : */
-
- if (cf) fclose(cf);
- if (df1) fclose(df1);
- if (df2) fclose(df2);
-
- return 0;
- }
-
- /* append_batch() : */
- /* This function will re-batch a uudebat or uucdebat into the given */
- /* batch (batchname). uucdebat jobs are uncompressed before they are */
- /* appended to the batch. */
-
- append_batch(jobname,df1_name,df2_name,is_uucdebat,batchname)
- char *df1_name,
- *df2_name,
- *batchname,
- *jobname;
-
- int is_uucdebat;
- {
- char cmdstr[256];
-
- /* Prepare the command to append batch contents to batch file : */
-
- if (is_uucdebat)
- sprintf(cmdstr, "uncompress -c < %s >> %s", df1_name, batchname);
- else
- sprintf(cmdstr, "cat %s >> %s", df1_name, batchname);
-
- /* execute the command, exit if non-zero exit status : */
-
- if (system(cmdstr))
- p_exit("error while uncompressing/appending batch",93);
-
- /* mark job's files for deletion : */
-
- strcpy(del_jobnames[jobs_this_batch],jobname);
- strcpy(del_df1_names[jobs_this_batch],df1_name);
- strcpy(del_df2_names[jobs_this_batch++],df2_name);
- }
-
- /* send_batch() : */
- /* This function will send off a batch. It will handle both compressed */
- /* and uncompressed batching, choosing between uudebat and uucdebat */
- /* as the uux'ed commands. Once successfully uux'ed, the batch's data */
- /* file and the data files of all jobs batched in it are deleted. */
-
- send_batch(batchname,nodename,compression_mode)
- char *batchname,*nodename;
- int compression_mode;
- {
- char cmdstr[256];
- int i;
-
- fprintf(stderr,"uubatch : sending batch...");
-
- /* Prepare the uux command : */
-
- if (compression_mode)
- sprintf(cmdstr, "compress -c %s | uux - -r %s!uucdebat",
- batchname, nodename);
- else
- sprintf(cmdstr, "uux - -r %s!uudebat < %s",
- nodename, batchname);
-
- /* Execute it : */
-
- if (system(cmdstr))
- p_exit("error while uux'ing batch",115);
-
- /* Remove batch temporary data file : */
-
- if (unlink(batchname))
- p_exit("error while removing batch file",120);
-
- /* Remove all data files of jobs batched in this batch : */
-
- for (i=0;i<jobs_this_batch;i++)
- {
- if (unlink(del_jobnames[i]) || unlink(del_df1_names[i]) ||
- unlink(del_df2_names[i]) )
- p_exit("error while deleting batched files",125);
-
- }
-
- /* restart job count : */
-
- jobs_this_batch = 0;
-
- fprintf(stderr,"batch sent.\n");
- }
-
- static int
- digest_args(argc,argv,compression_mode)
- int argc;
- char **argv;
- int *compression_mode;
- {
- int node_spec=0;
- char c,*p;
-
- /* the following externs are defined by getopt(3), look them up : */
-
- extern char *optarg;
- extern int optind;
-
- *compression_mode = 0;
- max_bytes = DF_MAX_BYTES;
- max_cbytes = DF_MAX_CBYTES;
- critical_size = DF_CRITICAL_SIZE;
-
- /* extract the path to uubatch's binary directory. uucplock is */
- /* assumed to be there : */
-
- strcpy(uubatch_bin_path,argv[0]);
- if (p = rindex(uubatch_bin_path,'/'))
- *p='\0';
-
- /* parse options : */
-
- while((c = getopt(argc, argv, "cB:C:S:T:")) != -1)
- switch(c)
- {
- case 'c' : *compression_mode = 1; break;
- case 'B' : max_bytes = atoi(optarg); break;
- case 'C' : max_cbytes = atoi(optarg); break;
- case 'S' : critical_size = atoi(optarg); break;
- case 'T' : min_time_before_batch = atoi(optarg); break;
- case '?' : return 1;
- }
-
- for (; optind < argc; optind++)
- {
- add_nodename(argv[optind]);
- node_spec = 1;
- }
-
- /* return error (true value) if no node or no bin dir is specified : */
-
- return (!node_spec);
- }
-
-
- /* main() : */
- /* */
- /* This is the main program. See top of file to find out what it does */
- /* */
- /* Usage : */
- /* uubatch [-c] [-B n] [-C n] [-S n] [-T n] node [node2...] */
- /* */
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- int i,compression_mode;
- char *jobname,*nodename,pathname[256];
- struct stat bfile_status;
- DIR *dirp;
- struct dirent *dp;
-
- /* do nit-picking checks and argument extraction : */
-
- if (digest_args(argc,argv,&compression_mode))
- p_exit(
- "Usage:\nuubatch [-c] [-B n] [-C n] [-S n] [-T n] node [node2...]"
- ,5);
-
-
- /* loop on all node names specified in args, and do rmail batching on */
- /* each one : */
-
- for(curr_node=first_node;curr_node;curr_node=curr_node->next)
- {
- nodename = curr_node->name;
-
- fprintf(stderr,"uubatch : Doing node %s\n",nodename);
-
- /* construct node's spool directory path : */
-
- strcpy(pathname,UUCP_SPOOL_DIR);
- strcat(pathname,"/");
- strcat(pathname,nodename);
-
- /* cd to node's spool directory : */
-
- if (chdir(pathname))
- pe_exit("Cannot cd to node's spool directory",78);
-
- /* put a uucp lock on the node, continue only if lock succeeds : */
-
- if (!lock_node(nodename))
- {
-
- tmpnam(batchname); /* Get a name for the batch file. */
-
- accumulated_size = total_rmail_jobs =
- jobs_this_batch = registered_batches = 0;
-
- /* open the batch file : */
-
- if (!(bfile=fopen(batchname,"w")))
- pe_exit("Can't temporary batch file",82);
-
- /* open the spool directory in order to search it : */
-
- dirp = opendir(pathname);
-
- /* loop on all jobs (searching the for C.* files): */
-
- while ( dp = readdir(dirp) )
- if (str_eq(jobname=dp->d_name,"C."))
- {
- fprintf(stderr,"uubatch : Doing file %s\n",jobname);
-
- /* If batch file if "full", send it and reset it : */
-
- if ( (accumulated_size>critical_size) ||
- (jobs_this_batch>MAX_JOBS_PER_BATCH) )
- {
- /* close the batch file, send it off, and open */
- /* a new one : */
-
- if (fclose(bfile))
- pe_exit("error closing batch file",85);
- send_batch(batchname,nodename,compression_mode);
- if (!(bfile=fopen(batchname,"w")))
- pe_exit("Can't temporary batch file",90);
- accumulated_size = 0;
- }
-
- /* Attempt to batch the current job in the loop : */
-
- batch_job(jobname);
- }
-
- /* now close the batch file : */
-
- if (fclose(bfile))
- pe_exit("error closing batch file",95);
-
- if (total_rmail_jobs) /* only re-batch registered jobs if needed.*/
- {
- /* loop on all registered jobs (eligable for re-batching in */
- /* terms of size and age) and re-batch them : */
-
- for (i=0;i<registered_batches;i++)
- {
- stat(batchname,&bfile_status); /* get batch file stats. */
-
- /* If batch file if "full",send it off and reset it : */
-
- if ( (bfile_status.st_size>critical_size) ||
- (jobs_this_batch>MAX_JOBS_PER_BATCH) )
- send_batch(batchname,nodename,compression_mode);
-
- /* re-batch the current registered batch in the loop : */
-
- append_batch(jobnames[i],df1_names[i],df2_names[i],
- jobs_uucdebat[i],batchname);
- }
-
- stat(batchname,&bfile_status); /* get batch file stats. */
-
- /* send batch if there is anything left (usually there is) :*/
-
- if (bfile_status.st_size>0)
- send_batch(batchname,nodename,compression_mode);
- }
- else /* if no rmail jobs, skipped batching : */
- pd("No rmail jobs, skip batching.",100);
-
- if (unlock_node(nodename))
- pds("unlock failed on node",nodename,110);
-
- } /* of if on successfull lock .*/
- else
- pds("lock failed on node",nodename,122);
-
- unlink(batchname);
-
- } /* of node loop. */
-
- /* bye bye : */
-
- my_exit(0);
- }
-